const input = {
    "a": 1,
    "b[0]": 1,
    "b[1]": 2,
    "b[2].c": true,
    "b[3][0]": 3,
    "d.e": 2,
    "d.f.e.g": 3,
    "e.j": 222,
    "e.k[0]": 1,
    "e.k[1]": 2,
    "e.k[2]": 3,
    "e.k[3].d": 32,
    "josie": "so cool"
}

const output = {
    a: 1,
    b: [ 1, 2, { c: true }, [ 3 ] ],
    d: { e: 2, f: 3 },
    g: null,
    e: {j: 222, k: [1,2,3,{d:32}]},
    f: undefined,
    h: '',
    josie: 'so cool'
}

function unFlatten(obj) {
    let result = {}
    if (typeof obj !== 'object') {
        return obj
    }
    //? 正则表达式 用于匹配非.和[]的和[]内的数
    const r = /\.?([^\.\[\]]+)|\[(\d+)\]/g
    //? 遍历属性
    for (const prop in obj) {
        //? 正则匹配结果
        let matches
        //? 将匹配结果作为key 初始化为""导致每次都会先进入""的value中
        let p = ""
        //? 用于深入的指针
        let cur = result
        //? 可能存在多个匹配结果
        while (matches = r.exec(prop)) {
            //? matches[2]代表第二组的匹配结果 matches[1]代表第一组
            //? 如果p不存在则新建 同一属性只新建一次（如b[0]和b[1]中的b）
            //? 这里cur直接进数组/对象中了
            cur = cur[p] || (cur[p] = matches[2] ? [] : {})
            //? p作为此次匹配的值
            p = matches[2] || matches[1]
        }
        //? 匹配完 把值给出去 这也是为什么要用cur来深入
        cur[p] = obj[prop]
    }
    //? 因为前面的设置p = "" 导致整个结果数组都有一个key值为""作为入口
    return result[""] || result
}
console.log(unFlatten(input))
